/* *****************************************************************
 *
 * Download latest Blinker library here:
 * https://github.com/blinker-iot/blinker-library/archive/master.zip
 * 
 * 
 * Blinker is a cross-hardware, cross-platform solution for the IoT. 
 * It provides APP, device and server support, 
 * and uses public cloud services for data transmission and storage.
 * It can be used in smart home, data monitoring and other fields 
 * to help users build Internet of Things projects better and faster.
 * 
 * Make sure installed 2.7.4 or later ESP8266/Arduino package,
 * if use ESP8266 with Blinker.
 * https://github.com/esp8266/Arduino/releases
 * 
 * Make sure installed 1.0.5 or later ESP32/Arduino package,
 * if use ESP32 with Blinker.
 * https://github.com/espressif/arduino-esp32/releases
 * 
 * Docs: https://diandeng.tech/doc
 *       
 * 
 * *****************************************************************
 * 
 * Blinker 库下载地址:
 * https://github.com/blinker-iot/blinker-library/archive/master.zip
 * 
 * Blinker 是一套跨硬件、跨平台的物联网解决方案，提供APP端、设备端、
 * 服务器端支持，使用公有云服务进行数据传输存储。可用于智能家居、
 * 数据监测等领域，可以帮助用户更好更快地搭建物联网项目。
 * 
 * 如果使用 ESP8266 接入 Blinker,
 * 请确保安装了 2.7.4 或更新的 ESP8266/Arduino 支持包。
 * https://github.com/esp8266/Arduino/releases
 * 
 * 如果使用 ESP32 接入 Blinker,
 * 请确保安装了 1.0.5 或更新的 ESP32/Arduino 支持包。
 * https://github.com/espressif/arduino-esp32/releases
 * 
 * 文档: https://diandeng.tech/doc
 *       
 * 
 * *****************************************************************/
#define BLINKER_ALIGENIE_OUTLET
#define BLINKER_WIFI
#include <SoftwareSerial.h>
#include <Blinker.h>

#define MSG_HEAD 0xAA //数据帧头

SoftwareSerial invented_serial(4, 5); //通常情况下，在 ESP8266 D1 mini 的引脚定义中，D1 引脚对应 GPIO5，D2 引脚对应 GPIO4。
                                      //所以，当你使用 SoftwareSerial 库并传入参数 4 和 5 时，实际上就是将 D2 引脚（GPIO4）设置为 Rx，D1 引脚（GPIO5）设置为 Tx。

char auth[] = "d3b6d3ec91b4";
char ssid[] = "Han";
char pswd[] = "000000000";

unsigned char comdata[128];   // 串口接收缓冲区
char phone[] = "18796974313";

#pragma pack(1)
typedef struct
{
  unsigned char sign1;//帧头
  unsigned char cmd;  //命令字 
  unsigned short len; //数据长度
  unsigned char data[];
}__attribute__((__packed__)) MSG_HEADER;
#define MSG_HEADER_LEN sizeof(MSG_HEADER)

typedef struct{
  int heart;          //心率值
  int spo;            //血氧值
  float temperature;  //体温值
  float pressure;     //血压值
  float angle;        //最大角
  float Longitude;    //经度
  float Latitude;     //纬度
}BODAY_MSG;
#define BODAY_MSG_LEN sizeof(BODAY_MSG)

typedef struct{
  unsigned char max_angle;//最大角度阈值
  unsigned char max_heart;//最大心率阈值
  unsigned char max_temp; //最大温度阈值
  unsigned char max_press;//最大血压阈值
}__attribute__((__packed__))SET_MSG;
#define SET_MSG_LEN sizeof(SET_MSG)

typedef struct{
  unsigned char alarm_angle;  //跌倒报警
  unsigned char alarm_heart;  //心率报警
  unsigned char alarm_temp;   //温度报警
  unsigned char alarm_press;  //血压报警
//  unsigned char alarm_turn;   //报警开关
}__attribute__((__packed__))ALARM_MSG;
#define ALARM_MSG_LEN sizeof(ALARM_MSG)

BODAY_MSG temp_body;
SET_MSG temp_set;
ALARM_MSG temp_alarm;

// 新建组件对象
BlinkerNumber HEART ("num-01");   // 心率组件
BlinkerNumber SPO   ("num-02");   // 血氧组件
BlinkerNumber TEMP  ("num-03");   // 温度组件
BlinkerNumber BP    ("num-04");   // 血压组件
BlinkerNumber ANGLE ("num-05");   // 最大角度
BlinkerNumber LONGITUDE ("num-06");// 经度组件
BlinkerNumber LATITUDE  ("num-07");// 纬度组件

BlinkerSlider MAX_ANGLE ("ran-01");// 角度上限
BlinkerSlider MAX_HEART ("ran-02");// 心率下限
BlinkerSlider MAX_TEMP  ("ran-03");// 温度下限
BlinkerSlider MAX_PRESS ("ran-04");// 血压上限

BlinkerButton ALARM_ANGLE ("btn-01");// 跌倒报警
BlinkerButton ALARM_HEART ("btn-02");// 心率报警
BlinkerButton ALARM_TEMP  ("btn-03");// 温度报警
BlinkerButton ALARM_PRESS ("btn-04");// 血压报警
BlinkerButton ALARM_TURN  ("btn-05");// 报警开关

void dataRead(const String & data)
{
    BLINKER_LOG("Blinker readString: ", data);
    Blinker.vibrate();
}

void heartbeat1()
{
    HEART.print(temp_body.heart);
    SPO.print(temp_body.spo);
    TEMP.print(temp_body.temperature);
    BP.print(temp_body.pressure);
    ANGLE.print(temp_body.angle);
    LONGITUDE.print(temp_body.Longitude);
    LATITUDE.print(temp_body.Latitude);
    Blinker.delay(100);
}
void heartbeat2()
{
    MAX_ANGLE.print(temp_set.max_angle);
    MAX_HEART.print(temp_set.max_heart);
    MAX_TEMP.print(temp_set.max_temp);
    MAX_PRESS.print(temp_set.max_press);
    Blinker.delay(100);
}

#define MAX_PRINTED_BIN_LENGTH 128
void LOG_binary(const char* data, int length)
{
    char buf[MAX_PRINTED_BIN_LENGTH * 3 + 10] = {0};
    int i = 0;

    for (i = 0; i < length && i < MAX_PRINTED_BIN_LENGTH; i++)
    {
        sprintf(buf + i * 3, "%02X", data[i]);
        buf[i * 3 + 2] = ' ';   //because sprintf will add a terminating null character at the end
    }

    if (i >= MAX_PRINTED_BIN_LENGTH)
    {
        sprintf(buf + i * 3, "%s", "......\n");
    }
    Serial.println(buf);
}

//发送数据到MCU
void Send_data_MCU(unsigned char cmd,unsigned char data)
{
    char string_temp[64];
    unsigned char check_sum = (unsigned char)(cmd + data);  //校验和计算
    unsigned char pack[6] = {MSG_HEAD,cmd,data,check_sum};
    
    //打印发送的数据包
    sprintf(string_temp,"SEND:%02X %02X %02X %02X",MSG_HEAD,cmd,data,check_sum);
    Serial.println(string_temp);

    //串口发送数据包
    invented_serial.write(pack,4);
}

//接收MCU数据
void Recive_data_MCU(void)
{
    char string_temp[128];
    unsigned char checksum = 0;
    int i;
    MSG_HEADER *msg = (MSG_HEADER *)comdata;

    //帧头校验
    if(msg->sign1 != MSG_HEAD){
      Serial.println("HEAD ERROR !!");
      return;
    }

    if(msg->cmd == 0x01)
    {
      //和校验
      for(i = 1; i < (MSG_HEADER_LEN + BODAY_MSG_LEN); i++){
          checksum += comdata[i];
      }
      if(msg->data[BODAY_MSG_LEN] != checksum){
        sprintf(string_temp,"CHECK ERROR %02X",checksum);
        Serial.println(string_temp);
        return;
      }
        BODAY_MSG *msg_body = (BODAY_MSG *)msg->data;
        //数据校验通过赋值
        temp_body.heart        = msg_body->heart;
        temp_body.spo          = msg_body->spo;
        temp_body.temperature  = msg_body->temperature;
        temp_body.pressure     = msg_body->pressure;
        temp_body.angle        = msg_body->angle;
        temp_body.Longitude    = msg_body->Longitude;
        temp_body.Latitude     = msg_body->Latitude;
        sprintf(string_temp,"Recive: 0x01 (%d ,%d ,%0.1f ,%0.1f ,%0.1f ,%0.4f ,%0.4f )",
          msg_body->heart,msg_body->spo,msg_body->temperature,msg_body->pressure,
          msg_body->angle,msg_body->Longitude,msg_body->Latitude);
        Serial.println(string_temp);
        heartbeat1();
        dataStorage();
    }
    else if(msg->cmd == 0x02)
    {
      //和校验
      for(i = 1; i < (MSG_HEADER_LEN + SET_MSG_LEN); i++){
          checksum += comdata[i];
      }
      if(msg->data[SET_MSG_LEN] != checksum){
        sprintf(string_temp,"CHECK ERROR %02X",checksum);
        Serial.println(string_temp);
        return;
      }
        SET_MSG *msg_set = (SET_MSG *)msg->data;
        //数据校验通过赋值
        temp_set.max_angle    = msg_set->max_angle;
        temp_set.max_heart    = msg_set->max_heart;
        temp_set.max_temp     = msg_set->max_temp;
        temp_set.max_press    = msg_set->max_press;
        
        sprintf(string_temp,"Recive: 0x02(%d ,%d ,%d ,%d )",
          msg_set->max_angle,msg_set->max_heart,msg_set->max_press,msg_set->max_temp);
        Serial.println(string_temp);
        heartbeat2();
    }
    else if(msg->cmd == 0x03)
    {
      //和校验
      for(i = 1; i < (MSG_HEADER_LEN + ALARM_MSG_LEN); i++){
          checksum += comdata[i];
      }
      if(msg->data[ALARM_MSG_LEN] != checksum){
        sprintf(string_temp,"CHECK ERROR %02X",checksum);
        Serial.println(string_temp);
        return;
      }
        ALARM_MSG *msg_alarm = (ALARM_MSG *)msg->data;
        //数据校验通过赋值 
        if(msg_alarm->alarm_angle)
        {
          ALARM_ANGLE.color("#FF69B4");
          ALARM_ANGLE.print("on");
          temp_alarm.alarm_angle    = msg_alarm->alarm_angle;
          sprintf(string_temp,"Value: %0.1f",temp_body.angle);
          Blinker.wechat("Title: Alarm", "State: angle alarm", string_temp); 
        }else if(msg_alarm->alarm_heart)
        {
          ALARM_HEART.color("#FF69B4");
          ALARM_HEART.print("on");
          temp_alarm.alarm_heart    = msg_alarm->alarm_heart;
          sprintf(string_temp,"Value: %d",temp_body.heart);
          Blinker.wechat("Title: Alarm", "State: heart rate alarm", string_temp); 
        }else if(msg_alarm->alarm_temp)
        {
          ALARM_TEMP.color("#FF69B4");
          ALARM_TEMP.print("on");
          temp_alarm.alarm_temp     = msg_alarm->alarm_temp;
          printf(string_temp,"Value: %0.1f",temp_body.temperature);
          Blinker.wechat("Title: Alarm", "State: temperature alarm", string_temp); 
        }else if(msg_alarm->alarm_press)
        {
          ALARM_PRESS.color("#FF69B4");
          ALARM_PRESS.print("on");
          temp_alarm.alarm_press    = msg_alarm->alarm_press;
          printf(string_temp,"Value:  %d",temp_body.pressure);
          Blinker.wechat("Title: Alarm", "State: pressure alarm", string_temp); 
        }

        sprintf(string_temp,"Recive: 0x03(%d ,%d ,%d ,%d )",
          msg_alarm->alarm_angle,msg_alarm->alarm_heart,msg_alarm->alarm_temp,msg_alarm->alarm_press);
        Serial.println(string_temp);
    }
}
void dataStorage(void){
    Blinker.dataStorage("cha-01",temp_body.heart);
    Blinker.dataStorage("cha-02",temp_body.temperature);
    Blinker.dataStorage("cha-03",temp_body.angle);
}

void MAX_ANGLE_callback(const int state) {
    BLINKER_LOG("get state: ", state);
    temp_set.max_angle=(unsigned char)state;
    Send_data_MCU(0x01,(unsigned char)state);
}
void MAX_HEART_callback(const int state) {
    BLINKER_LOG("get state: ", state);
    temp_set.max_heart=(unsigned char)state;  
    Send_data_MCU(0x02,(unsigned char)state);
}
void MAX_TEMP_callback(const int state) {
    BLINKER_LOG("get state: ", state);
    temp_set.max_temp=(unsigned char)state;  
    Send_data_MCU(0x03,(unsigned char)state);
}
void MAX_PRESS_callback(const int state) {
    BLINKER_LOG("get state: ", state);
    temp_set.max_press=(unsigned char)state;  
    Send_data_MCU(0x04,(unsigned char)state);
}
void ALARM_TURN_callback(const String & state) {
    BLINKER_LOG("get state: ", state);
    ALARM_ANGLE.color("#D3D3D3");
    ALARM_HEART.color("#D3D3D3");
    ALARM_TEMP.color("#D3D3D3");
    ALARM_PRESS.color("#D3D3D3");
    
    ALARM_ANGLE.print("on");
    ALARM_HEART.print("on");
    ALARM_TEMP.print("on");
    ALARM_PRESS.print("on");
}
void setup()
{
    // 初始化串口
    Serial.begin(115200);
    invented_serial.begin(115200);
    BLINKER_DEBUG.stream(Serial);
    BLINKER_DEBUG.debugAll();

    // 初始化有LED的IO
    pinMode(LED_BUILTIN, OUTPUT);
    digitalWrite(LED_BUILTIN, HIGH);
    
    // 初始化blinker
    Blinker.begin(auth, ssid, pswd);
    Blinker.attachData(dataRead);
    Blinker.attachHeartbeat(heartbeat1);
    Blinker.attachDataStorage(dataStorage);
    MAX_ANGLE.attach(MAX_ANGLE_callback);
    MAX_HEART.attach(MAX_HEART_callback);
    MAX_TEMP.attach(MAX_TEMP_callback);
    MAX_PRESS.attach(MAX_PRESS_callback);
//    Blinker.sms("Hello blinker! Button pressed!", phone);
    ALARM_TURN.attach(ALARM_TURN_callback);
    Blinker.connect();
    
}

unsigned long _time;
void loop() {
    Blinker.run();
    if((millis()- _time)%2000 == 0)
    {
      _time = millis();
      if(Blinker.connected())
      {
        digitalWrite(LED_BUILTIN, LOW);
      }
      else
      {
        digitalWrite(LED_BUILTIN, HIGH);
      }
      if(temp_body.Longitude >= 1)
      {
        Blinker.gps(temp_body.Longitude,temp_body.Latitude);
      }
    }

    
    int i=0;
    while (invented_serial.available() > 0){
        comdata[i] = (unsigned char)(invented_serial.read());  //每次读一个char字符，并相加
        i++;
        delay(2);
    }
    if (i > 0){
        Recive_data_MCU();//打印接收到的字符
        Serial.print("BIN: ");
        LOG_binary((char *)comdata,i+1);
        memset(comdata,0,128);
    }
}
